/*
 * @Author: zhaoqr
 * @Date: 2024-06-27
 * @LastEditTime: 2024-06-27
 * @LastEditors: zhaoqr zhaoqr@channelsoft.com
 * @Description: 
 * @FilePath: \vue3-template\src\utils\this.js
 */

Function.prototype.myCall = function (context, ...args) {
  // 确保调用者是一个函数
  if (typeof this !== 'function') {
    throw new TypeError('myCall must be called on a function');
  }

  // 设置上下文，默认为全局对象（浏览器环境下为window）
  context = context || globalThis;

  // 在目标上下文中创建一个唯一的属性，用于存储原函数，并调用它
  const key = Symbol();
  context[key] = this;

  // 执行函数，并传递参数
  const result = context[key](...args);

  // 删除临时添加的属性
  delete context[key];

  // 返回函数执行结果
  return result;
};

Function.prototype.myApply = function (context, args = []) {
  // 类似于 myCall 的检查
  if (typeof this !== 'function') {
    throw new TypeError('myApply must be called on a function');
  }

  // 设置上下文，默认为全局对象
  context = context || globalThis;

  // 使用 Symbol 创建临时属性存储原函数
  const key = Symbol();
  context[key] = this;

  // 根据规范，args 应该是一个数组或类数组对象，这里直接使用 spread 操作符传递
  const result = context[key](...args);

  // 清理
  delete context[key];

  return result;
};

Function.prototype.myBind = function (context, ...boundArgs) {
  // 类似于之前的检查
  if (typeof this !== 'function') {
    throw new TypeError('myBind must be called on a function');
  }

  // 返回一个新的函数，这个函数在调用时会使用预先设定的上下文和参数
  return function (...args) {
    // 使用 apply 来确保新函数能正确接收剩余的参数
    return this.myApply(context, boundArgs.concat(args));
  }.bind(this); // 确保新函数的`this`绑定为原函数
};


const obj = {
  name: 'obj',
  eat: function (food) {
    console.log(`${this.name} is eating ${food}`);
  },
};
const name = 'window';

obj.eat('apple'); // obj is eating apple
obj.eat.myCall(); // window is eating undefined
